package com.neusoft.bizcore.license.service.impl;

import java.io.EOFException;
import java.io.File;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.prefs.Preferences;

import javax.annotation.PostConstruct;
import javax.security.auth.x500.X500Principal;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.neusoft.bizcore.license.bean.LicenseCreateBean;
import com.neusoft.bizcore.license.config.BizcoreLicenseProperties;
import com.neusoft.bizcore.license.service.LicenseVerifyService;

import de.schlichtherle.license.CipherParam;
import de.schlichtherle.license.DefaultCipherParam;
import de.schlichtherle.license.DefaultKeyStoreParam;
import de.schlichtherle.license.DefaultLicenseParam;
import de.schlichtherle.license.KeyStoreParam;
import de.schlichtherle.license.LicenseContent;
import de.schlichtherle.license.LicenseManager;
import de.schlichtherle.license.LicenseParam;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class LicenseVerifyServiceImpl implements LicenseVerifyService {

    @Autowired
    private BizcoreLicenseProperties property;

    private final DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Getter
    @Setter
    private boolean verified = false;

    private final static X500Principal DEFAULTHOLDERANDISSUER = new X500Principal(
            "CN=databus, OU=neusoft, O=neusoft, L=DL, S=LN, C=CN");

    @Override
    public File create(LicenseCreateBean licenseCreateBean) {
        final LicenseManager licenseManager = new LicenseManager(this.initLicenseParam0(licenseCreateBean));
        try {
            final File temp = File.createTempFile("license", "lic");
            licenseManager.store((this.createLicenseContent(licenseCreateBean)), temp);
            return temp;
        } catch (final Exception e) {
            LicenseVerifyServiceImpl.log.error("", e);
        }
        return null;
    }

    @PostConstruct
    @Override
    public LicenseContent install() {
        LicenseContent result = null;
        try {

            final LicenseManager licenseManager = new LicenseManager(this.initLicenseParam(this.property));
            // 先卸载证书 == 给null
            licenseManager.uninstall();
            // 安装
            final ClassLoader classLoader = this.getClass().getClassLoader();
            final URL url = classLoader.getResource(this.property.getLicensePath());
            result = licenseManager.install(new File(url.getFile()));
            LicenseVerifyServiceImpl.log.info("license install success, valid date range：{} - {}",
                    this.format.format(result.getNotBefore()),
                    this.format.format(result.getNotAfter()));
            this.verified = true;
        } catch (final Exception e) {
            String error = "";
            if (e instanceof EOFException) {
                error = "file is damage.";
                LicenseVerifyServiceImpl.log.error("license install unsuccess. " + error);
            } else {
                LicenseVerifyServiceImpl.log.error("license install unsuccess.", e);
            }
        }
        return result;
    }

    @Override
    public boolean verify() {
        final LicenseManager licenseManager = new LicenseManager(this.initLicenseParam(this.property));
        try {
            final LicenseContent licenseContent = licenseManager.verify();
            LicenseVerifyServiceImpl.log.info("license verify success, valid date range：{0} - {1}",
                    this.format.format(licenseContent.getNotBefore()),
                    this.format.format(licenseContent.getNotAfter()));
            this.setVerified(true);
            return true;
        } catch (final Exception e) {
            LicenseVerifyServiceImpl.log.error("license verify unsuccess. ", e);
            this.setVerified(false);
            return false;
        }
    }

    private LicenseParam initLicenseParam0(LicenseCreateBean licenseCreateBean) {
        final Preferences preferences = Preferences.userNodeForPackage(LicenseVerifyServiceImpl.class);
        final CipherParam cipherParam = new DefaultCipherParam(licenseCreateBean.getStorePass());
        final KeyStoreParam privateStoreParam =
                new DefaultKeyStoreParam(LicenseVerifyServiceImpl.class, licenseCreateBean.getStorePath(),
                        licenseCreateBean.getAlias(), licenseCreateBean.getStorePass(), licenseCreateBean.getKeyPass());

        return new DefaultLicenseParam(licenseCreateBean.getSubject(), preferences, privateStoreParam, cipherParam);
    }

    private LicenseContent createLicenseContent(LicenseCreateBean licenseCreateBean) {
        LicenseContent content = null;
        content = new LicenseContent();
        content.setSubject(licenseCreateBean.getSubject());
        content.setHolder(LicenseVerifyServiceImpl.DEFAULTHOLDERANDISSUER);
        content.setIssuer(LicenseVerifyServiceImpl.DEFAULTHOLDERANDISSUER);

        content.setIssued(licenseCreateBean.getIssuedTime());

        final Calendar instance = Calendar.getInstance();
        instance.setTime(licenseCreateBean.getIssuedTime());
        instance.add(Calendar.DAY_OF_YEAR, licenseCreateBean.getDays());
        content.setNotBefore(licenseCreateBean.getIssuedTime());
        content.setNotAfter(instance.getTime());
        content.setConsumerType(licenseCreateBean.getConsumerType());
        content.setConsumerAmount(licenseCreateBean.getConsumerAmount());
        content.setInfo(licenseCreateBean.getInfo());
        content.setExtra(new Object());
        return content;
    }

    private LicenseParam initLicenseParam(BizcoreLicenseProperties param) {
        final Preferences preferences = Preferences.userNodeForPackage(LicenseVerifyServiceImpl.class);
        final CipherParam cipherParam = new DefaultCipherParam(param.getStorePass());
        final KeyStoreParam publicStoreParam =
                new DefaultKeyStoreParam(LicenseVerifyServiceImpl.class, param.getPublicKeysStorePath(),
                        param.getPublicAlias(), param.getStorePass(), null);

        return new DefaultLicenseParam(param.getSubject(), preferences, publicStoreParam, cipherParam);
    }

}
